package com.oristartech.netty.common.dispatcher;

import com.oristartech.netty.common.message.RequestMessage;
import com.oristartech.netty.common.message.ResponseMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StopWatch;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 ** 响应结果监听类，用于返回请求响应结果
 *
 * @author: chenfenghai
 * @version: 1.0
 * @date: 2020-03-13 13:37
 * @blame Team
 */
@Slf4j
public class ResponseFuture implements Future<ResponseMessage> {

    /** 响应超时时间，单位为毫秒，生产环境应用使用配置参数传入 */
    private static final long RESPONSE_TIMEOUT_MILLI = 60_000;
    /** 因为请求和响应是一一对应的，因此初始化CountDownLatch值为1。 */
    private CountDownLatch countDownLatch = new CountDownLatch(1);
    /** 响应计时器，用于计算响应时间 */
    private StopWatch stopWatch;
    /** 通道发送，用于处理响应超时时，移除ChannelSender.RESPONSE_FUTURE_MAP中对应的MAP */
    private ChannelSender channelSender;
    /** 请求消息，以ID为KEY */
    private RequestMessage request;
    /** 响应结果 */
    private ResponseMessage response;

    /**
     ** 无参数构造方法
     */
    private ResponseFuture(){
        throw new IllegalArgumentException("未实现无参数构造方法，请使用有参数的构造方法");
    }

    /**
     ** 构造方法，在NettyResponseChannelHandler类上进行注册当前响应结果监听类
     *
     * @param channelSender 渠道发送
     * @param requestMessage 请求消息
     */
    public ResponseFuture(ChannelSender channelSender, RequestMessage requestMessage){
        this.request = requestMessage;
        this.channelSender = channelSender;
        this.stopWatch = new StopWatch(requestMessage.getId());
        this.stopWatch.start();
    }

    /**
     ** 取消，未实现处理，默认为false
     *
     * @param mayInterruptIfRunning 是否中断正在运行的线程
     * @return false
     */
    @Override
    public boolean cancel(boolean mayInterruptIfRunning) {
        return false;
    }

    /**
     ** 是否取消，未实现处理，默认为false
     *
     * @return false
     */
    @Override
    public boolean isCancelled() {
        return false;
    }

    /**
     ** 是否完成
     *
     * @return 如果存在响应结果则返回true，否则返回false
     */
    @Override
    public boolean isDone() {
        return response != null;
    }

    /**
     ** 等待获取结果
     *
     * @return 响应结果
     */
    @Override
    public ResponseMessage get() throws InterruptedException {
        return get(RESPONSE_TIMEOUT_MILLI, TimeUnit.MILLISECONDS);
    }

    /**
     ** 等待获取结果
     *
     * @param timeout 超时时间值
     * @param unit 超时时间单位
     * @return 响应结果
     */
    @Override
    public ResponseMessage get(long timeout, TimeUnit unit) throws InterruptedException {
        try {
            if(countDownLatch.await(timeout, unit)){
                return this.response;
            }
        }finally {
            channelSender.remove(request.getId());
            // 打印响应用时
            stopWatch.stop();
            log.info("请求[{}]响应时间(millis)：{}", stopWatch.getId(), stopWatch.getTotalTimeMillis());
        }
        return null;
    }

    /**
     ** 接收响应结果，并让计数器减一
     *
     * @param response 响应结果
     */
    public void received(ResponseMessage response) {
        this.response = response;
        countDownLatch.countDown();
    }
}
